///////////////////////////////////////////////////////////////////////////////
// Includes
#include <tchar.h>
#include <guiGraphicsDisplayEmulator.h>
#include <drvIOConfig.h>

///////////////////////////////////////////////////////////////////////////////
// Const

///////////////////////////////////////////////////////////////////////////////
// Module global variables
static DWORD	l_thread_id			= 0;
static HANDLE	l_thread_handle = NULL;
static HWND		l_hwnd					= 0;

///////////////////////////////////////////////////////////////////////////////
// Function prototypes
static void ThreadRoutine( void* in_param );
static HWND CreateEmuWindow(void);

///////////////////////////////////////////////////////////////////////////////
// Functions
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Init emulator window
void guiInitDisplayEmulatorDriver(void)
{
	l_thread_handle = CreateThread( NULL,
																	0,
																	(LPTHREAD_START_ROUTINE)ThreadRoutine,
																	NULL,
																	0,
																	&l_thread_id );
}

///////////////////////////////////////////////////////////////////////////////
// Postpone emulator thread
void guiDisableEmulatorThread(void)
{
	if( l_thread_handle != NULL )
		SuspendThread( l_thread_handle );
}

///////////////////////////////////////////////////////////////////////////////
// Resume thread
void guiEnableEmulatorThread(void)
{
	if( l_thread_handle != NULL )
		ResumeThread( l_thread_handle );
}

///////////////////////////////////////////////////////////////////////////////
// Update canvas
void guiUpdateCanvas( dosInt16 in_left, dosInt16 in_top, dosInt16 in_right, dosInt16 in_bottom )
{
	if( l_hwnd != NULL )
	{
		HDC hdc = GetDC( l_hwnd );

		if( hdc != NULL )
			guiRefreshScreen( hdc );

		ReleaseDC( l_hwnd, hdc );
	}
}

///////////////////////////////////////////////////////////////////////////////
// Is emulator running
dosBool IsEmulatorRunning(void)
{
	Sleep(0);

	return l_thread_handle != NULL;
}

///////////////////////////////////////////////////////////////////////////////
// Internal functions
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
// Window message handler
static LRESULT CALLBACK WindowMessageHandler(	HWND		in_hwnd,
																							UINT		in_message,
																							WPARAM	in_wparam,
																							LPARAM	in_lparam )
{
  switch (in_message)
  {
		case WM_CREATE:
		{
			// set size
			RECT work_area;
			RECT owner_rect;
			HWND owner_hwnd;
			RECT client_rect;
			RECT window_rect;
			int width, height;
			int left, top;

			// set window size
			GetClientRect(in_hwnd, &client_rect);
			GetWindowRect(in_hwnd, &window_rect );

			width = window_rect.right - window_rect.left;
			height = window_rect.bottom - window_rect.top;

			width		= guiSCREEN_WIDTH * guiemu_ZOOM + width - client_rect.right;
			height	= guiSCREEN_HEIGHT * guiemu_ZOOM + height - client_rect.bottom;

			owner_hwnd = GetDesktopWindow();

			GetWindowRect( owner_hwnd, &owner_rect );

			left = ( owner_rect.left + owner_rect.right	- width		) / 2;
			top = ( owner_rect.top  + owner_rect.bottom	- height	) / 2;

			// center within screen coordinates
			SystemParametersInfo(SPI_GETWORKAREA, 0, &work_area, 0);

			if( left < work_area.left )
				left = work_area.left;

			if( top < work_area.top )
				top = work_area.top;

			if( left + width > work_area.right )
				left = work_area.right - width;

			if( top + height> work_area.bottom )
				top = work_area.bottom - height;

			SetWindowPos( in_hwnd,
										NULL,
										left,
										top,
										width, height,
										SWP_NOZORDER | SWP_NOACTIVATE);
		}
		break;

    case WM_PAINT:
			{
				PAINTSTRUCT ps;
				HDC hdc;

				hdc = BeginPaint(in_hwnd, &ps);

				guiRefreshScreen(hdc);

				EndPaint(in_hwnd, &ps);
			}
			break;

		case WM_DESTROY:
			PostQuitMessage(0);
			guiDIBDriverCleanUp();
      break;

		case WM_KEYDOWN:
			guiProcessKey( (in_lparam & (1<<24)) != 0, (dosChar)in_wparam );
			break;

		default:
      return DefWindowProc(in_hwnd, in_message, in_wparam, in_lparam);
      break;
    }

    return 0;
}

///////////////////////////////////////////////////////////////////////////////
// Create window
static HWND CreateEmuWindow(void)
{
	HWND hwnd;

	// register class
	WNDCLASSEX wcex;

	wcex.cbSize					= sizeof(WNDCLASSEX);
	wcex.style          = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc    = WindowMessageHandler;
	wcex.cbClsExtra     = 0;
	wcex.cbWndExtra     = 0;
	wcex.hInstance      = 0;
	wcex.hIcon          = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));
	wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName   = NULL;
	wcex.lpszClassName  = _T("dosDisplayEmulationWindow");
	wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_APPLICATION));

  if(!RegisterClassEx(&wcex))
  {
		MessageBox(NULL, _T("Call to RegisterClassEx failed!"), _T("dosEmuWin"), 0);

    return 0;
  }

	// create window
	hwnd= CreateWindow(	_T("dosDisplayEmulationWindow"),
											_T("Domino Operation System Emulation"),
											WS_OVERLAPPEDWINDOW | WS_DLGFRAME | WS_SYSMENU | WS_MINIMIZEBOX,
											CW_USEDEFAULT, CW_USEDEFAULT,
											0, 0,
											NULL,
											NULL,
											0,
											NULL );
	if( !hwnd )
	{
		MessageBox(NULL, _T("Call to CreateWindow failed!"), _T("Win32 Guided Tour"), 0);

    return 0;
	}

	if( hwnd != 0 )
	{
		ShowWindow(hwnd, SW_SHOWNORMAL);
		UpdateWindow(hwnd);
	}

	return hwnd;
}

///////////////////////////////////////////////////////////////////////////////
// Thread functions
static void ThreadRoutine( void* in_param )
{
	MSG msg;
	
	l_hwnd = CreateEmuWindow();

	if( l_hwnd != 0 )
	{
		// Main message loop:
		while (GetMessage(&msg, NULL, 0, 0)) 
		{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
				Sleep(0);
		}
	}

	if( l_hwnd != 0 )
		DestroyWindow( l_hwnd );

	l_thread_id			= 0;
	l_thread_handle = NULL;

	ExitThread( 0 );
}